package com.stm.bi.report;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.stm.bi.core.util.DateUtils;
import com.stm.bi.enums.ProductStructIndex;
import com.stm.bi.model.BaseOriginData;
import com.stm.bi.model.ChartOriginData;
import com.stm.bi.model.ChartTotalData;
import com.stm.bi.model.ProductStructureParam;
import com.stm.framework.annotation.Param;
import com.stm.framework.core.tookit.BeanToolkit;
import com.stm.framework.core.util.ClassUtil;
import com.stm.framework.core.util.StringUtil;
import com.stm.framework.excel.util.ParamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.stm.saas.constant.IndexConstants.BUSINESS_ID_FIELD_NAME;
import static com.stm.saas.constant.IndexConstants.DATE_FIELD_NAME;

public class ProductChartHandle<T extends BaseOriginData> {

    private static final String TOTAL_FILED_NAME = "total";
    private static final String TOTAL_SHOW_NAME = "合计";
    private static final String NAME = "name";


    private final Class<T> clazz;

    public ProductChartHandle(Class<T> clazz) {
        this.clazz = clazz;
    }


    private static final Logger log = LoggerFactory.getLogger(ProductChartHandle.class);

    /**
     * map转对象
     *
     * @param map
     * @return
     */
    public T mapToBean(Map<String, Object> map) {
        try {
            if (map == null || this.clazz == null) {
                throw new IllegalArgumentException("Map or Class cannot be null");
            }
            T obj = this.clazz.getDeclaredConstructor().newInstance();
            for (Field field : this.clazz.getDeclaredFields()) {
                field.setAccessible(true);
                // 获取字段的驼峰名称
                String camelName = field.getName();

                // 逆向转换：驼峰 -> 下划线（生成可能的数据库字段名）
                String underscoreName = camelToUnderscore(camelName);

                // 优先尝试驼峰字段名
                Object value = map.containsKey(camelName) ? map.get(camelName)
                        : map.get(underscoreName); // 其次尝试下划线字段名

                if (value != null) {
                    field.set(obj, value);
                }
            }
            return obj;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 驼峰转下划线工具方法
    private static String camelToUnderscore(String str) {
        return str.replaceAll("([a-z0-9])([A-Z])", "$1_$2").toLowerCase();
    }

    /**
     * 原数据格式处理
     *
     * @param dataList
     * @param param
     * @return
     */
    public List<ChartOriginData<T>> handleOriginData(List<Map> dataList, ProductStructureParam param, List<String> dateList) {
        List<ChartOriginData<T>> originDataList = new ArrayList<>();
        // 编码一致，名字不一致，改名导致重复日期数据处理
        Map<String, ChartOriginData<T>> originDataMap = new LinkedHashMap<>();
        for (Map map : dataList) {
            T originData = (T) this.mapToBean(map);
            originData.initData();

            ChartOriginData<T> chartOriginData = new ChartOriginData<>();
            if (!map.containsKey(param.getBusinessField()) || map.get(param.getBusinessField()) == null) {
                continue;
            }
            String businessId = map.get(param.getBusinessField()).toString();
            chartOriginData.setData(originData)
                    .setBusinessValue(businessId)
                    .setBusinessName(StringUtil.isNotEmpty(map.get(param.getBusinessFieldName())) && !"null".equals(map.get(param.getBusinessFieldName())) ?
                            map.get(param.getBusinessFieldName()).toString() : businessId)
                    .setDateDataValue(map.get(DATE_FIELD_NAME).toString())
                    .setDateDataName(map.get(DATE_FIELD_NAME).toString());
            // 处理重复日期数据
            String key = chartOriginData.getDateDataValue() + "&" + businessId;
            if (originDataMap.containsKey(key)) {
                // 合计改名前数据
                ChartOriginData<T> oldData = originDataMap.get(key);
                oldData.getData().totalQty((JSONObject) JSON.toJSON(originData), "date");
            } else {
                originDataMap.put(key, chartOriginData);
                originDataList.add(chartOriginData);
            }

        }

        // 补全日期数据
        if (param.getNeedComplete()) {
            this.completeDateOriginData(dateList, originDataList);
        }

        return originDataList;
    }

    /**
     * 补全空缺的日期数据
     *
     * @param dateList
     * @param originDataList
     */
    private void completeDateOriginData(List<String> dateList, List<ChartOriginData<T>> originDataList) {
        // 补充空缺的日期
        Map<String, List<ChartOriginData<T>>> businessMap = originDataList.stream().collect(Collectors.groupingBy(ChartOriginData::getBusinessValue));
        originDataList.clear();
        businessMap.forEach((businessValue, businessList) -> {
            Map<String, ChartOriginData<T>> rowMap = businessList.stream().collect(Collectors.toMap(ChartOriginData::getDateDataValue, Function.identity()));
            String businessName = "";

            for (String date : dateList) {
                ChartOriginData<T> chartOriginData;
                if (rowMap.containsKey(date)) {
                    businessName = rowMap.get(date).getBusinessName();
                    chartOriginData = rowMap.get(date);
                } else {
                    chartOriginData = new ChartOriginData<>();
                    T data = this.mapToBean(new HashMap<>());
                    data.initData();
                    chartOriginData.setBusinessValue(businessValue)
                            .setBusinessName(StringUtil.isNotEmpty(businessName) ? businessName : businessValue)
                            .setDateDataValue(date)
                            .setDateDataName(date)
                            .setData(data);
                }
                originDataList.add(chartOriginData);
            }
        });
    }

    /**
     * 颜色分组处理
     *
     * @param dataList
     * @param param
     * @return
     */
    public List<ChartOriginData<T>> handleColorData(List<Map> dataList, ProductStructureParam param) {
        List<ChartOriginData<T>> colorDataList = new ArrayList<>();
        for (Map map : dataList) {
            T originData = (T) this.mapToBean(map);
            originData.initData();

            ChartOriginData<T> chartOriginData = new ChartOriginData<>();
            String businessId = StringUtil.isNotEmpty(map.get("color_code")) && !"null".equals(map.get("color_code")) ? map.get("color_code").toString() : map.get("prod_code").toString();
            String businessName = StringUtil.isNotEmpty(map.get("color_code")) && !"null".equals(map.get("color_code")) ? map.get("color_code").toString() : businessId;
            chartOriginData.setData(originData)
                    .setBusinessValue(businessId)
                    .setBusinessName(businessName)
                    .setDateDataValue(map.get(DATE_FIELD_NAME).toString())
                    .setDateDataName(map.get(DATE_FIELD_NAME).toString());
            colorDataList.add(chartOriginData);
        }
        return colorDataList;
    }


    /**
     * 按行去合计数据
     *
     * @param dataResult
     * @param businessTotalList
     * @param param
     * @return
     */
    public void handleRowByBusinessId(List<Map<String, String>> dataResult, List<ChartTotalData<T>> businessTotalList, ProductStructureParam param) {
        // 按行转化
        businessTotalList.forEach(rowTotalData -> {
            Map<String, String> row = new LinkedHashMap<>();
            makeShowDataByRow(param, rowTotalData, row);
            dataResult.add(row);
        });
    }

    private void makeShowDataByRow(ProductStructureParam param, ChartTotalData<T> rowTotalData, Map<String, String> row) {
        row.put(BUSINESS_ID_FIELD_NAME, rowTotalData.getCode());
        row.put(NAME, rowTotalData.getName());

        if (ProductStructIndex.DIGESTIBILITY.equals(param.getProductStructIndex() )
                || ProductStructIndex.RETURN_RATE.equals(param.getProductStructIndex())) {
            rowTotalData.getDataList().forEach(data -> {
                if (data.getData().getFieldValue1() != null && data.getData().getFieldValue1().compareTo(BigDecimal.ZERO) != 0) {
                    row.put(data.getDateDataValue(), data.getData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP).toPlainString() + param.getUnit());
                }
            });
            if (rowTotalData.getTotalData().getFieldValue1() != null && rowTotalData.getTotalData().getFieldValue1().compareTo(BigDecimal.ZERO) != 0) {
                row.put(TOTAL_FILED_NAME, rowTotalData.getTotalData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP).toPlainString() + param.getUnit());
            }
        } else {
            rowTotalData.getDataList().forEach(data -> {
                if (data.getData().getFieldValue1() != null) {
                    row.put(data.getDateDataValue(), data.getData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP).toPlainString() + param.getUnit());
                }
            });
            if (rowTotalData.getTotalData().getFieldValue1() != null) {
                row.put(TOTAL_FILED_NAME, rowTotalData.getTotalData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP).toPlainString() + param.getUnit());
            }
        }
    }

    /**
     * 颜色按行转化
     *
     * @param businessTotalList
     * @param param
     * @return
     */
    public Map<String, Map<String, String>> handleRowByColorCode(List<ChartTotalData<T>> businessTotalList, ProductStructureParam param) {
        // 格式转化处理
        Map<String, Map<String, String>> colorMap = new LinkedHashMap<>();
        // 按行转化
        businessTotalList.forEach(rowTotalData -> {
            if (!colorMap.containsKey(rowTotalData.getCode())) {
                colorMap.put(rowTotalData.getCode(), new LinkedHashMap<>());
            }
            Map<String, String> row = colorMap.get(rowTotalData.getCode());
            makeShowDataByRow(param, rowTotalData, row);
        });
        return colorMap;
    }

    /**
     * 第一行总合计处理
     *
     * @param dateTotalList
     * @param param
     */
    public ChartTotalData<T> handleRowByTotal(List<ChartTotalData<T>> dateTotalList, ProductStructureParam param) {
        // 第一行合计处理
        List<ChartOriginData<T>> sumChartData = dateTotalList.stream().map(item -> {
            ChartOriginData<T> chartOriginData = new ChartOriginData<>();
            chartOriginData.setData(item.getTotalData())
                    .setDateDataValue(item.getCode())
                    .setDateDataName(item.getName())
                    .setBusinessValue(TOTAL_FILED_NAME)
                    .setBusinessName(TOTAL_SHOW_NAME);
            return chartOriginData;
        }).collect(Collectors.toList());
        List<ChartTotalData<T>> allTotalChartData = this.handleBusinessTotal(sumChartData, "date", param.getNeedCumulative());
        if (!allTotalChartData.isEmpty()) {
            return allTotalChartData.get(0);
        }
        return null;
    }


    /**
     * 图表数据处理
     *
     * @param dataList
     * @param param
     * @return
     */
    public List<Map<String, String>> handleTableData(List<Map> dataList, ProductStructureParam param, List<String> dateList) {
        log.debug("原始数据：" + JSON.toJSONString(dataList));
        List<Map<String, String>> dataResult = new ArrayList<>();
        if (dataList.isEmpty()) {
            Map<String, String> row = new LinkedHashMap<>();
            row.put(BUSINESS_ID_FIELD_NAME, TOTAL_FILED_NAME);
            row.put(NAME, TOTAL_SHOW_NAME);
            dataResult.add(row);
            return dataResult;
        }

        // 原数据转化
        List<ChartOriginData<T>> chartOriginData = this.handleOriginData(dataList, param, dateList);
        // 按business统计
        List<ChartTotalData<T>> businessTotalList = this.handleBusinessTotal(chartOriginData, "business", param.getNeedCumulative());
        // 按日期统计
        List<ChartTotalData<T>> dateTotalList = this.handleDateTotal(chartOriginData);
        // 第一行合计数据
        ChartTotalData<T> allChartTotalData = this.handleRowByTotal(dateTotalList, param);
        businessTotalList.add(0, allChartTotalData);
        log.debug("最后处理结果：" + JSON.toJSONString(businessTotalList));
        // 打印具体数据
//        printTotalData(businessTotalList);
        // 格式化处理
        // 按行转化
        this.handleRowByBusinessId(dataResult, businessTotalList, param);

        return dataResult;
    }

    private void printTotalData(List<ChartTotalData<T>> businessTotalList) {
        for (ChartTotalData<T> data : businessTotalList) {
            data.getDataList().forEach(item -> {
                System.out.println("行名：" + item.getBusinessName() + "，日期：" + item.getDateDataValue() + "，数据：" + this.printData(item.getData()));
            });
            System.out.println("行名：" + data.getName() + "，日期：最后一列，数据：" + this.printData(data.getTotalData()));
        }
    }


    /**
     * 打印底层数据
     * @param data
     * @return
     */
    public String printData(T data) {
        StringBuilder showData = new StringBuilder();
        List<Field> fields = ClassUtil.getDeclaredFields(data.getClass());
        // 遍历对象的所有字段
        for (Field field : fields) {
            // 获取字段的旧值和新值
            Object value = ClassUtil.getFieldValue(data, field);
            // 如果旧值和新值不相同，则将更新项添加到updateItems列表中

            Param param1 = ParamUtil.getParam(data.getClass(), field);
            String showName;
            if (param1 == null) {
                showName = field.getName();
            } else {
                showName = param1.label();
            }
            showData.append(showName).append(":").append(value).append("，");

        }
        return showData.toString();
    }

    /**
     * 颜色数据处理
     *
     * @param dataList
     * @param param
     * @param dateList
     * @return
     */
    public Map<String, Map<String, String>> handleColorData(List<Map> dataList, ProductStructureParam param, List<String> dateList) {
        // 颜色原数据
        List<ChartOriginData<T>> colorOriginData = this.handleColorData(dataList, param);

        Map<String, List<ChartOriginData<T>>> colorList = colorOriginData.stream().collect(Collectors.groupingBy(ChartOriginData::getBusinessValue));
        List<ChartOriginData<T>> colorTotalList = new ArrayList<>();
        colorList.forEach((key, value) -> {
            List<ChartTotalData<T>> dateTotalData = this.handleDateTotal(value);
            dateTotalData.forEach(dateData -> {
                ChartOriginData<T> data = new ChartOriginData<>();
                data.setDateDataValue(dateData.getCode());
                data.setDateDataName(dateData.getName());
                data.setBusinessValue(key);
                data.setBusinessName(dateData.getDataList().get(0).getBusinessName());
                data.setData(dateData.getTotalData());
                colorTotalList.add(data);
            });
        });

        // 补全日期数据
        if (param.getNeedComplete()) {
            this.completeDateOriginData(dateList, colorTotalList);
        }
        List<ChartTotalData<T>> colorSumList = this.handleBusinessTotal(colorTotalList, "date", param.getNeedCumulative());

        return this.handleRowByColorCode(colorSumList, param);

    }

    /**
     * 图标数据处理
     *
     * @param dataList
     * @param param
     * @param dateList
     * @return
     */
    public List<List<Object>> handleChartData(List<Map> dataList, ProductStructureParam param, List<String> dateList) {
        List<List<Object>> datas = new ArrayList<>();
        Map<String, ChartOriginData<T>> dateMap;
        BigDecimal resultTotal;
        if (dataList.isEmpty()) {
            dateMap = new HashMap<>();
            resultTotal = param.getDefaultValue().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP);
        } else {
            // 原数据转化
            List<ChartOriginData<T>> chartOriginData = this.handleOriginData(dataList, param, dateList);
            // 按business统计
            List<ChartTotalData<T>> businessTotalList = this.handleBusinessTotal(chartOriginData, "business", param.getNeedCumulative());
            ChartTotalData<T> dataTotal = businessTotalList.isEmpty() ? new ChartTotalData<>() : businessTotalList.get(0);
            resultTotal = dataTotal.getTotalData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP);
            dateMap = dataTotal.getDataList().stream().collect(Collectors.toMap(ChartOriginData::getDateDataValue, Function.identity()));
        }
        // 合计放第一行
        List<Object> totalRow = new ArrayList<>();
        totalRow.add(param.getTotalName());
        totalRow.add(resultTotal.toPlainString() + param.getUnit());
        datas.add(totalRow);

        for (String date : dateList) {
            List<Object> row = new ArrayList<>();
            row.add(DateUtils.getReportDateName(date, param.getDateType().getValue()));

            if (dateMap.containsKey(date)) {
                row.add(dateMap.get(date).getData().getFieldValue1().multiply(param.getCoefficient()).setScale(param.getScaleNum(), RoundingMode.HALF_UP));
            } else {
                row.add(0);
            }
            if (!ProductStructIndex.DIGESTIBILITY.equals(param.getProductStructIndex() )
                    && ! ProductStructIndex.RETURN_RATE.equals(param.getProductStructIndex())) {
                row.add(resultTotal);
            }
            datas.add(row);
        }
        return datas;
    }


    /**
     * 按业务ID去合计数据
     *
     * @param originDataList
     * @param totalType
     * @return
     */
    public List<ChartTotalData<T>> handleBusinessTotal(List<ChartOriginData<T>> originDataList, String totalType, Boolean isCumulative) {
        originDataList.sort(Comparator.comparing(ChartOriginData::getDateDataValue));
        Map<String, ChartTotalData<T>> totalDataMap = new LinkedHashMap<>();
        for (ChartOriginData<T> originData : originDataList) {
            ChartTotalData<T> chartTotalData;
            if (totalDataMap.containsKey(originData.getBusinessValue())) {
                chartTotalData = totalDataMap.get(originData.getBusinessValue());
                chartTotalData.setName(originData.getBusinessName());
                // 累加
                chartTotalData.getTotalData().totalQty((JSONObject) JSON.toJSON(originData.getData()), totalType);
            } else {
                chartTotalData = new ChartTotalData<>();
                chartTotalData.setCode(originData.getBusinessValue())
                        .setName(originData.getBusinessName())
                        .setDataList(new ArrayList<>())
                        .setTotalData(BeanToolkit.instance().copy(originData.getData(), this.clazz));
                totalDataMap.put(originData.getBusinessValue(), chartTotalData);
            }
            if (isCumulative) {
                // 记录累计
                originData.getData().cumulativeData((JSONObject) JSON.toJSON(chartTotalData.getTotalData()), totalType);
            }
            chartTotalData.getDataList().add(originData);
            chartTotalData.setSortNum(chartTotalData.getTotalData().getSortNum());
        }

        List<ChartTotalData<T>> resultList = totalDataMap.values().stream()
                .sorted(Comparator.comparing(ChartTotalData::getSortNum)).collect(Collectors.toList());
        Collections.reverse(resultList);
        log.debug("处理业务行：" + JSON.toJSONString(resultList));
        return resultList;
    }

    /**
     * 按日期去合计数据
     *
     * @param originDataList
     * @return
     */
    public List<ChartTotalData<T>> handleDateTotal(List<ChartOriginData<T>> originDataList) {
        originDataList.sort(Comparator.comparing(ChartOriginData::getDateDataValue));
        Map<String, ChartTotalData<T>> totalDataMap = new LinkedHashMap<>();
        for (ChartOriginData<T> originData : originDataList) {
            ChartTotalData<T> chartTotalData;
            if (totalDataMap.containsKey(originData.getDateDataValue())) {
                chartTotalData = totalDataMap.get(originData.getDateDataValue());
                chartTotalData.getTotalData().totalQty((JSONObject) JSON.toJSON(originData.getData()), "date");
            } else {
                chartTotalData = new ChartTotalData<>();
                chartTotalData.setCode(originData.getDateDataValue())
                        .setName(originData.getDateDataName())
                        .setDataList(new ArrayList<>())
                        .setTotalData(BeanToolkit.instance().copy(originData.getData(), this.clazz));
                totalDataMap.put(originData.getDateDataValue(), chartTotalData);
            }
            chartTotalData.getDataList().add(originData);
        }

        List<ChartTotalData<T>> resultList = totalDataMap.values().stream()
                .sorted(Comparator.comparing(ChartTotalData::getCode)).collect(Collectors.toList());
        log.debug("时间业务列：" + JSON.toJSONString(resultList));
        return resultList;
    }
}
